package controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import persistence.ProductoMapper;
import view.PrendaPanel;
import view.ListaProductosPanel;
import model.Material;
import model.Prenda;
import model.PrendaSinTemporada;
import model.PrendaTemporada;

public class PrendaController {
	private List<Prenda> prendas;

	private MaterialController materialController;
	private static PrendaController instance;
	private PrendaPanel prendaPanel;
	private boolean fullyLoaded = false;
	
	private PrendaController() {
		prendas = new ArrayList<Prenda>();
		materialController = MaterialController.getInstance();
	}
	
	public static PrendaController getInstance() {
		if(instance == null) {
			instance = new PrendaController();
		}
		
		return instance;
	}
	

	/**
	 * Alta de una PrendaTemporada en el sistema. El codigo es unico, por lo tanto no debe existir ya una prenda con el mismo codigo.
	 * @param codigo codigo que representa univocamente a la prenda
	 * @param nombre nombre de la prenda
	 * @param materiales como clave se utiliza el material y el valor almacenado es la cantidad de material utilizado en la prenda 
	 * @param stock stock de la prenda
	 * @param temporada temporada de la prenda
	 * @return <b>true</b> en caso de que el alta haya sido efectiva, <b>false</b> si ya existia una prenda con el mismo codigo o se produce un error
	 */
	public boolean altaPrendaTemporada(String codigo, String nombre, Map<Material, Integer> materiales, int stock, String temporada) {
		boolean result = false;
		if(buscarPrenda(codigo) == null) {
			PrendaTemporada altaPrenda;
			altaPrenda = new PrendaTemporada(codigo, nombre, materiales, stock, temporada);
			result = altaPrenda.guardar();
			prendas.add(altaPrenda);
		} 
		return result;
	}

	/**
	 * Alta de una PrendaSinTemporada en el sistema. El codigo es unico, por lo tanto no debe existir ya una prenda con el mismo codigo.
	 * @param codigo codigo que representa univocamente a la prenda
	 * @param nombre nombre de la prenda
	 * @param materiales como clave se utiliza el material y el valor almacenado es la cantidad de material utilizado en la prenda 
	 * @param stock stock de la prenda
	 * @return <b>true</b> en caso de que el alta haya sido efectiva, <b>false</b> si ya existia una prenda con el mismo codigo
	 */
	public boolean altaPrendaSinTemporada(String codigo, String nombre, Map<Material, Integer> materiales, int stock) {
		boolean result = false;
		if(buscarPrenda(codigo) == null){
			PrendaSinTemporada altaPrenda;
			altaPrenda = new PrendaSinTemporada(codigo, nombre, materiales, stock);
			result = altaPrenda.guardar();
			prendas.add(altaPrenda);
		}
		
		return result;	
	}
	
	/**
	 * Baja de la prenda con el codigo recibido.
	 * @param codigo codigo de la prenda a dar de baja
	 * @return <b>true</b> en caso de que la baja haya sido efectiva, <b>false</b> si no encontro una prenda con el codigo recibido
	 */
	public boolean bajaPrenda(String codigo) {
		boolean result = false;
		Prenda prendaBaja = buscarPrenda(codigo);
		if (prendaBaja != null){
			prendas.remove(prendaBaja);
			result = prendaBaja.eliminar();
		}
		return result;
		
	}
	
	/**
	 * Modificaciones de los atributos de una PrendaTemporada y el listado de materiales que la componen. Debe existir una prenda con el codigo recibido.
	 * @param codigo codigo que representa univocamente a la prenda
	 * @param nombre nombre de la prenda
	 * @param materiales listado de materiales que componen a la prenda
	 * @param stock stock de la prenda
	 * @param temporada temporada de la prenda
	 */
	public boolean modificacionPrendaTemporada(String codigo, String nuevoCodigo, String nombre, Map<Material, Integer> materiales, int stock, String temporada) {
		boolean result = false;
		PrendaTemporada modificada = (PrendaTemporada)buscarPrenda(codigo);
		if(modificada != null) {
			modificada.setCodigo(nuevoCodigo);
			modificada.setNombre(nombre);
			modificada.setCantidadStock(stock);
			modificada.setTemporada(temporada);
			modificada.agregarMateriales(materiales);
			result = modificada.modificar();
		}
		return result;
	}

	/**
	 * Modificaciones de los atributos de una PrendaSinTemporada y el listado de materiales que la componen. Debe existir una prenda con el codigo recibido.
	 * @param codigo codigo que representa univocamente a la prenda
	 * @param nombre nombre de la prenda
	 * @param materiales listado de materiales que componen a la prenda
	 * @param stock stock de la prenda
	 */
	public boolean modificacionPrendaSinTemporada(String codigo, String nuevoCodigo, String nombre, Map<Material, Integer> materiales, int stock) {
		boolean result = false;
		PrendaSinTemporada modificada = (PrendaSinTemporada)buscarPrenda(codigo);
		if(modificada != null) {
			modificada.setCodigo(nuevoCodigo);
			modificada.setNombre(nombre);
			modificada.setCantidadStock(stock);
			modificada.agregarMateriales(materiales);
			result = modificada.modificar();
		}

		return result;
	}

	/**
	 * Busqueda de una prenda con el codigo recibido.
	 * @param codigo codigo de la prenda a buscar
	 * @return <b>null</b> en caso de que no exista una prenda con el codigo recibido, la Prenda correspondiente al codigo buscado
	 */
	public Prenda buscarPrenda(String codigo){
		Prenda result = null;
		
		for(Prenda prenda: getPrendas()) {
			if(prenda.hasCodigo(codigo)) {
				result = prenda;
				break;
			}
		}
		
		return result;
	}
	
	/**
	 * Metodo que retorna todas las prendas existentes
	 * @return List<Prenda> prendas
	 */
	public List<Prenda> getPrendas() {
		if(!fullyLoaded) {
			prendas = ProductoMapper.getInstance().buscarPrendas();
			fullyLoaded = true;
		}
		return prendas;
	}
	
	public void altaPrendaPanel() {
		prendaPanel = new PrendaPanel(materialController.getMateriales());
		prendaPanel.showPanel();
	}

	public boolean mostrarPrenda(String codigo) {
		boolean result = false;
		Prenda prenda = buscarPrenda(codigo);
		if (prenda != null) {
			prendaPanel = new PrendaPanel(materialController.getMateriales(), prenda);
			prendaPanel.showPanel();
			result = true;
		}
		return result;
	}

	public void mostrarPrendas() {
		ListaProductosPanel productosPanel = new ListaProductosPanel(getPrendas(), "Prendas");
		productosPanel.showPanel();
	}
}
